/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#ifndef __XOS_STL_PROTOCOL_PACKAGE_PKG_RET_LIST_BASE_RES_H__
#define __XOS_STL_PROTOCOL_PACKAGE_PKG_RET_LIST_BASE_RES_H__

#include <string>
#include "../../import/head.h"
#include "../../tools/head.h"
#include "../db/db_get.h"
#include "pkg_public_functions.h"
#include "pkg_base_res.h"

namespace xos_protocol
{

    template< class CHILD, class T, class PACKER, class SESSION, class DATA, class PACKAGE >
    class pkg_base_ret_list_res : public pkg_base_res<
        pkg_base_ret_list_res< CHILD, T, PACKER, SESSION, DATA, PACKAGE >,
        SESSION,
        DATA,
        PACKAGE >
    {
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        typedef pkg_base_ret_list_res< CHILD, T, PACKER, SESSION, DATA, PACKAGE > THIS_CHILD;
        typedef pkg_base_res<
            THIS_CHILD,
            SESSION,
            DATA,
            PACKAGE > BASE;
        enum enumField
        {
            FIELD_NUM = 64
        };

    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 

        pkg_base_ret_list_res( xos_box::i_serial * pSerial, xos_container::i_container * pContainer, int nProtocol, int nMaxPackageHeadLen ) :
            BASE( pSerial, pContainer, nProtocol ),
            n_max_package_head_len( nMaxPackageHeadLen )
        {
            for( unsigned int i = 0; i < sizeof( fields ) / sizeof( fields[0] ); ++i )
            {
                fields[i] = 0;
            }
            field_num = 0;
            page_size = 0;
            page_num = 0;
            cur_page = 0;
        }

        ~pkg_base_ret_list_res()
        {
            list_data.clear();
        }

    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        typename T::ITER list_data_begin;
        typename T::LIST list_data;
        uint8_t fields[FIELD_NUM];
        uint8_t field_num;
        int n_max_package_head_len;
        uint16_t page_size;
        uint16_t page_num;
        uint16_t cur_page;

    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        int helper_dis_compose( xos_box::i_buf * pBuf )
        {
            CHILD * pThis = static_cast<CHILD*>( this );
            return pThis->helper_dis_compose( pBuf );
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        int helper_proc( int nCookie, SESSION * pSession )
        {
            int ret = 0;

            CHILD * pThis = static_cast<CHILD*>( this );

            size_t tBegin = page_size * cur_page;
            size_t tEnd = tBegin + page_size;
            typename T::LIST d_list;
            typename T::ITER begin;
            typename T::ITER end;

            if( 0 == ret )
            {
                pThis->filter_list_by_data();
            }

            if( 0 == ret )
            {
                d_list.swap( list_data );
                begin = d_list.begin();
                end = d_list.end();
            }

            if( ( 0 == ret ) && ( tBegin > d_list.size() ) )
            {
                tBegin = d_list.size();
            }

            if( ( 0 == ret ) && ( tEnd > d_list.size() ) )
            {
                tEnd = d_list.size();
            }

            if( ( 0 == ret ) && ( page_size > 0 ) )
            {
                size_t tLen = d_list.size();
                size_t tNum = tLen / page_size;
                if( tLen > tNum * page_size )
                {
                    tNum++;
                }
                page_num = ( uint16_t )tNum;
            }

            if( ( 0 == ret ) && ( page_size > 0 ) )
            {
                end = begin;
                std::advance( begin, tBegin );
                std::advance( end, tEnd );
            }

            for( typename T::ITER iter = begin; ( 0 == ret ) && ( iter != end ); ++iter )
            {
                T * pT = *iter;
                list_data.push_back( pT );
            }

            if( 0 == ret )
            {
                list_data_begin = list_data.begin();
            }

            return ret;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        int helper_compose( int nCookie, xos_box::i_buf * pBuf, bool & bFinished )
        {
            int ret = 0;

            if( 0 == BASE::n_ret )
            {
                ret = greedy_pack_list( BASE::n_protocol,
                    nCookie,
                    list_data_begin,
                    list_data.end(),
                    BASE::serial_ptr,
                    BASE::xos_ptr,
                    field_num,
                    fields,
                    list_data.size(),
                    page_size,
                    page_num,
                    cur_page,
                    n_max_package_head_len,
                    pBuf );
                if( list_data_begin != list_data.end() )
                {
                    bFinished = false;
                }
            }

            // 
            // 返回失败
            // 
            if( 0 != BASE::n_ret )
            {
                xos_protocol::db_get< T, PACKER > obj( BASE::serial_ptr, pBuf );
                obj.m_err = BASE::str_err;
                ret = obj.res_compose( nCookie, BASE::n_protocol, BASE::n_ret );
            }

            return ret;
        }

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int helper_done( DATA * pData )
        {
            CHILD * pThis = static_cast<CHILD*>( this );
            return pThis->helper_done( pData );
        }

    protected:
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int greedy_pack_list( int nProtocol, int nCookie, typename T::ITER & begin, typename T::ITER end,
            xos_box::i_serial * pSerial,
            xos::i_xos * pApi,
            uint8_t uFieldNum,
            uint8_t Fields[],
            size_t tTotalNum,
            int nPageSize,
            int nPageNum,
            int nCurPage,
            int nPackageHeadLen,
            xos_box::i_buf * pBuf )
        {
            int ret = 0;

            db_get< T, PACKER > obj( BASE::serial_ptr, pBuf );
            int nThisNum = 0;

            int nNumAbsolutePosInBuf = 0;
            int nBufPos = 0;
            int nBufLen = 0;

            if( 0 == ret )
            {
                obj.page_size = ( uint16_t )nPageSize;
                obj.page_num = ( uint16_t )nPageNum;
                obj.cur_page = ( uint16_t )nCurPage;
                obj.total_num = ( uint32_t )tTotalNum;
                obj.set_fields( uFieldNum, Fields );
            }

            if( 0 == ret )
            {
                ret = obj.res_compose( nCookie, nProtocol, 0 );
            }

            if( 0 == ret )
            {
                // 在这里还不知道一共打多少条数据
                // 等打完了再回这里添进打了多少条
                // 先打个0进去，再记一下这个绝对位置
                nNumAbsolutePosInBuf = pBuf->get_pos( 0 );
                int len = pBuf->get_len( 0 );
                // 减去pack进去数值为0的this_num的2字节
                len -= 2;
                nNumAbsolutePosInBuf += len;
            }

            if( 0 == ret )
            {
                ret = obj.pack_begin( nBufPos, nBufLen );
            }

            //[ tpoic id(4)+uid(4)+uname(n)+fid(4)+fname(n)+fnum(2)+title(n)+ptm(n)+mtm(n)+ftm(n)+r(1)+w(1)+d(1) ]
            // pack函数出错说明已经超过缓冲区边界了，就不要再打了，已经打的放弃，以后重打就行了
            while( ( 0 == ret ) && ( begin != end ) )
            {
                T * pTT = *begin;
                int r = obj.res_compose_data( pTT );
                r = obj.pack_end( nBufPos, nBufLen, r, nPackageHeadLen );
                if( 0 == r )
                {
                    nThisNum++;
                    begin++;
                }
                else
                {
                    break;
                }
            }

            if( ( 0 == ret ) && ( nThisNum > 0 ) )
            {
                // 在这里已经知道一共打多少条数据，如果不是0条，就重打一下
                ret = obj.pack_int16( &nNumAbsolutePosInBuf, nThisNum );
            }

            return ret;
        }

    };

} // xos_protocol

#endif // __XOS_STL_PROTOCOL_PACKAGE_PKG_RET_LIST_BASE_RES_H__
